
local core     = require("apisix.core")
local jwt      = require("resty.jwt")


local string_format = string.format
local ngx      = ngx
local pairs = pairs



-- 默认字串常量表
local str_const = {
    plugin_name = "jwt-payload-header", --插件名
    default_prefix = "jwt-payload-",    -- 默认前缀
    invalid_jwt= "invalid jwt string",  -- 错误信息
    regex_join_msg = "%s.%s",       -- 分割字串
    regex_join_delim = "([^%s]+)",  
    regex_split_dot = "%."
}

local schema = {
    type = "object",
    properties = {
        header = {
            type = "string", -- 如果从头部取，header名称
            default = "authorization"       --默认值
        },
        query = {           -- 如果从请求参数取，query-param名称
            type = "string",
            default = "jwt" --默认值
        },
        cookie = {
            type = "string", -- ditto
            default = "jwt"  --默认值
        },
        prefix ={
            type= "string",
            default=str_const.default_prefix,   -- 配置默认前缘
        },
        map={
            type = "object" --映射表
            
 
        }
    },

}


local _M = {
    version = 0.1,
    priority = 2511,
    type = 'auth',                  -- 为了能在rewrite阶段处理（jwt同阶段），这里只能auth,但这不是必然的
    name = str_const.plugin_name,   -- 配置插件名
    schema = schema,                -- 配置schema
    consumer_schema = schema        -- 消费者配置schema
}




-- check_schema 配置检查
function _M.check_schema(conf, schema_type)
    core.log.info("input conf: ", core.json.delay_encode(conf))
    if schema_type == core.schema.TYPE_CONSUMER then
        -- 消费者配置
        return core.schema.check(consumer_schema, conf)
    else
        -- 其他配置
        return core.schema.check(schema, conf)
    end
end

-- fetch_jwt_token 获取请求中的token
local function fetch_jwt_token(conf, ctx)
    local token = core.request.header(ctx, conf.header)
    if token then
        local prefix = sub_str(token, 1, 7)
        if prefix == 'Bearer ' or prefix == 'bearer ' then
            return sub_str(token, 8)
        end

        return token
    end

    token = ctx.var["arg_" .. conf.query]
    if token then
        return token
    end

    local val = ctx.var["cookie_" .. conf.cookie]
    if not val then
        return nil, "JWT not found in cookie"
    end
    return val
end

-- @function split string
local function split_string(str, delim)
    local result = {}
    local sep = string_format(str_const.regex_join_delim, delim)
    for m in str:gmatch(sep) do
      result[#result+1]=m
    end
    return result
  end


-- @function parse token - this can be  JWT token
-- @param token string
-- @return payload table
local function parse(  token_str)
    local tokens = split_string(token_str, str_const.regex_split_dot)
    local num_tokens = #tokens
    if num_tokens == 3 then
     return jwt:jwt_decode(tokens[2],true)
    else
      error({reason=str_const.invalid_jwt})
    end
  end
-- rewrite 重写阶段
function _M.rewrite(conf, ctx)
    local jwt_token, err = fetch_jwt_token(conf, ctx)
    if not jwt_token then
        core.log.info("failed to fetch JWT token: ", err)
        return
    end

    

    local payload = parse(jwt_token)
    if not payload then
        return
    end
  
   for k, v in pairs(payload) do
        local header = conf.map[k]
        if header then
            ngx.req.set_header(conf.prefix..header,v)
        else
            -- 测试时，用来看有哪些payload带过来了
            -- ngx.req.set_header(k, v)
        end
    end
    
    core.log.info("hit "..str_const.plugin_name .." rewrite")
    -- 查看配置的
    -- return 401, core.json.delay_encode(conf)
end





return _M
